package com.wy.panda.common.sign;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.MediaType;

import com.wy.panda.common.model.R;
import com.wy.panda.common.sign.constant.AuthConstants;
import com.wy.panda.common.sign.constant.Handler;
import com.wy.panda.common.sign.constant.SignLocationEnum;
import com.wy.panda.common.sign.constant.SubmitWayEnum;
import com.wy.panda.common.util.StringUtils;
import com.wy.panda.exception.PandaAccessDeniedException;

/**
 * 签名验证
 *
 * @author WangYuan
 * @since 2020年11月5日 下午3:10:44
 */
public class PandaSignValidator implements AuthConstants {

	/**
	 * 签名验证
	 */
	public boolean validate(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		SignLocationEnum signLocation = SignLocationEnum.PARAMETER;
		String appKeyCheckFlag = request.getParameter(REQUEST_APP_KEY);
		if(StringUtils.isBlank(appKeyCheckFlag)) {
			appKeyCheckFlag = request.getHeader(REQUEST_HEADER_APP_KEY);
			if(StringUtils.isBlank(appKeyCheckFlag)) {
				sendAuthError(response, new PandaAccessDeniedException("auth info is not exist, request is invalidate."));
				return false;
			}
			signLocation = SignLocationEnum.HEADER;
		}
		
		SubmitWayEnum submitWay = SubmitWayEnum.FORM;
		if(request.getContentType().toLowerCase().startsWith(MediaType.APPLICATION_JSON_VALUE)) {
			submitWay = SubmitWayEnum.JSON;
		}
		
		ISignValidationHandler handler = getHandler(signLocation, submitWay);
		if(handler == null) {
			sendAuthError(response, new PandaAccessDeniedException("Unsupported Request Way."));
			return false;
		}
		
		return handler.handle(request, response);
	}
	
	private ISignValidationHandler getHandler(SignLocationEnum signLocation, SubmitWayEnum submitWay) {
		ISignValidationHandler result = null;
		for(ISignValidationHandler item : PandaSignConfig.signValidationHandler()) {
			Handler annotation = item.getClass().getAnnotation(Handler.class);
			if(annotation == null) {
				continue;
			}
			
			if(annotation.signLocation().equals(signLocation) && annotation.submitWay().equals(submitWay)) {
				result = item;
				break;
			}
		}
		
		return result;
	}
	
	public void sendAuthError(HttpServletResponse response, Exception e) throws IOException {
		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
		
		PrintWriter writer = response.getWriter();
		writer.write(R.error(e.getMessage()).toJSONString());
		response.flushBuffer();
	}
}
